#include "Precomp.h"
#include "ltMapObject.h"
#include "ltPluggableFactory.h"
#include "ltMapState.h"
#include "mapformat.pb.h"
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/construct.hpp>

using namespace boost;
using namespace Ogre;

namespace Lotus
{
	MapObject::MapObject()
		:map(0),active(false),node(0),parent(0)
	{
	}

	MapObject::~MapObject()
	{
		if(!(this->name.empty()))
			getMap()->objectWidthNames.erase(this->name);
		std::for_each(childObjectList.begin(),childObjectList.end(),
			lambda::bind(lambda::delete_ptr(),lambda::_1));//delete all children
	}

	MapObject* MapObject::clone() const
	{
		mapformat::MapObject data;
		SaveData sdata(&data);
		onSave(sdata);
		MapObject* newEnt=map->loadObject(&data,0);
		return newEnt;
	}

	void MapObject::onMapBegin(){}
	void MapObject::onMapEnd(){}
	void MapObject::onUpdate(){}
	void MapObject::onChildAttached(MapObject* child){}
	void MapObject::onChildDetached(MapObject* child){}
	void onLoad(const SaveData& saveData){};
	void onSave(SaveData& saveData) const{};

	void MapObject::attachTo(MapObject* _parent)
	{
		if(parent)
		{
			parent->childObjectList.remove(this);//free this object from the old parent
			parent->onChildDetached(this);//inform the parent
		}
		else
			map->removeObject(this);//free this object from the map

		parent=_parent;
		if(parent)
		{
			parent->childObjectList.push_back(this);//add this object to the new parent
			parent->onChildAttached(this);//inform the parent
		}
		else
			map->addObject(this);//add this object to the map
	}

	MapObject* MapObject::getParent()
	{
		return parent;
	}

	void MapObject::setNode(Ogre::SceneNode* newNode)
	{
		if(node)
			node->setUserAny(Ogre::Any((MapObject*)0));//reset user data
		node=newNode;
		if(node)
		{
			Ogre::Any any(this);
			node->setUserAny(any);
		}
	}

	const Ogre::Vector3 MapObject::getRotation() const
	{
		const Ogre::Quaternion& quart=node->getOrientation();
		return Ogre::Vector3(quart.getPitch().valueDegrees(),quart.getRoll().valueDegrees(),quart.getYaw().valueDegrees());
	}
	#define DEG2RAD(X) (X)/180.f*3.14159265f
	void MapObject::setRotation(const Ogre::Vector3& rot)
	{
		node->pitch(Radian(DEG2RAD(rot.x)),Node::TS_PARENT);
		node->roll(Radian(DEG2RAD(rot.y)),Node::TS_PARENT);
		node->yaw(Radian(DEG2RAD(rot.z)),Node::TS_PARENT);
	}

	const Ogre::Vector3& MapObject::getPosition() const
	{
		return node->getPosition();
	}

	void MapObject::setPosition(const Ogre::Vector3& pos)
	{
		node->setPosition(pos);
	}

	const Ogre::Vector3&  MapObject::getScale() const
	{
		return node->getScale();
	}

	void MapObject::setScale(const Ogre::Vector3& scale)
	{
		node->setScale(scale);
	}
	#undef DEG2RAD
	void MapObject::setName(const char* name)
	{
		if(!(this->name.empty()))
			map->objectWidthNames.erase(this->name);
		this->name = name;
		if(!(this->name.empty()))
			map->objectWidthNames[this->name]=this;
	}

	const std::string& MapObject::getName() const
	{
		return name;
	}

	MapState* MapObject::getMap() const
	{
		return map;
	}
}